#pragma once

#include "dsegen.h"
#include "Edge.h"
#include "Image.h"
#include "FindNeighbor.h"
#include "DsegenTypes.h"

namespace dhis
{
	//------------------------------------------------------------------------------
	class CNeighbor 
	{
	public:
		CNeighbor();
		CNeighbor(const CNeighbor& o);
		CNeighbor& operator=(const CNeighbor& o);
		~CNeighbor(void) { }

		inline void Init( const int& id, const int& npix,const REAL& dissim,const REAL& perim=0.0)
		{
			m_id = id;
			m_numpix = npix;
			m_dissimCrit = dissim;
			m_mergedPerim = perim;
		}
	public:
		int     m_id;
		int     m_numpix;
		REAL m_dissimCrit;
		REAL m_mergedPerim;
	};
	
	//------------------------------------------------------------------------------
	typedef std::list<CNeighbor>                NeighborList;

	//------------------------------------------------------------------------------
	inline bool operator == (const CNeighbor& lhs, const CNeighbor& rhs)
	{
		return (lhs.m_id == rhs.m_id);
	}

	//------------------------------------------------------------------------------
	inline bool operator == (const CNeighbor& lhs, const int& id)
	{
		return (lhs.m_id == id);
	}

	//------------------------------------------------------------------------------
	inline bool operator == (const int& id, const CNeighbor& rhs)
	{
		return (id == rhs.m_id);
	}

	//------------------------------------------------------------------------------
	inline bool operator < (const CNeighbor& lhs, const CNeighbor& rhs)
	{
		if (lhs.m_dissimCrit == rhs.m_dissimCrit)
		{
			return lhs.m_numpix < rhs.m_numpix;
		}
		return lhs.m_dissimCrit < rhs.m_dissimCrit;
	}

	//------------------------------------------------------------------------------
	inline bool operator > (const CNeighbor& lhs, const CNeighbor& rhs)
	{
		if (lhs.m_dissimCrit == rhs.m_dissimCrit)
		{
			return lhs.m_numpix > rhs.m_numpix;
		}
		return lhs.m_dissimCrit > rhs.m_dissimCrit;
	}

	//------------------------------------------------------------------------------
	class CBoundaryLine {
	public:
		CBoundaryLine(void);
		CBoundaryLine(const int& row,const int& colStart,const int& colEnd);
		CBoundaryLine(const CBoundaryLine& other);
		CBoundaryLine& operator=(const CBoundaryLine& other);
		~CBoundaryLine(void) { }
	public:
		inline bool CBoundaryLine::Contains(const int& col,const int& row) const
		{
			if (row != m_row) return false;
			return ( (col >= m_colStart) && (col <= m_colEnd));
		}
	public:
		int m_row;
		int m_colStart;
		int m_colEnd;
	};

	//------------------------------------------------------------------------------
	typedef std::vector<CBoundaryLine>  BoundaryLineVec;

	//------------------------------------------------------------------------------
	inline bool operator < (const CBoundaryLine& lhs, const CBoundaryLine& rhs)
	{
		if(lhs.m_row != rhs.m_row) {
			return (lhs.m_row < rhs.m_row);
		} else {
			return (lhs.m_colStart < rhs.m_colStart);
		}
	}

	//------------------------------------------------------------------------------
	inline bool operator > (const CBoundaryLine& lhs, const CBoundaryLine& rhs)
	{
		if(lhs.m_row != rhs.m_row) {
			return (lhs.m_row > rhs.m_row);
		} else {
			return (lhs.m_colStart > rhs.m_colStart);
		}
	}

	//------------------------------------------------------------------------------
	class CRegionObject {
	public:
		CRegionObject();
		CRegionObject(const int & id);
		CRegionObject(const CRegionObject& other);
		CRegionObject& operator=(const CRegionObject& other);
		~CRegionObject();
	public:
		void Clear();
		inline void SetId(const int& label) { m_id = label; }
		inline int GetId() const { return m_id; }
		inline int& NumPixel() { return m_numpix; }
		inline const int& NumPixel() const { return m_numpix; }

		inline bool IsExistNeighbor(const int& nbid) const { return (std::find(m_neighbors.begin(),m_neighbors.end(),nbid) != m_neighbors.end()); }
		inline bool IsExistNeighbor(const CNeighbor& nbr) const { return (std::find(m_neighbors.begin(),m_neighbors.end(),nbr) != m_neighbors.end()); }

		inline NeighborList::iterator FindNeighbor(const int& nbid) { return std::find(m_neighbors.begin(),m_neighbors.end(),nbid); }
		inline NeighborList::iterator FindNeighbor(const CNeighbor& nbr) { return std::find(m_neighbors.begin(),m_neighbors.end(),nbr); }

		void AddNeighbor(const CNeighbor& nbr);
		bool DeleteNeighbor(const int& nbid);
		bool DeleteNeighbor(const CNeighbor& nbr);
				
		inline void SortNeighbor() { m_neighbors.sort(); }

		inline NeighborList& GetNeighbors() { return m_neighbors; }
		inline const NeighborList& GetNeighbors() const { return m_neighbors; }

		inline int GetRasterCount() const { return m_sum.size(); }
		inline REAL GetSum(const int& band) const { return m_sum[band]; }
		inline void SetSum(const int& band, const REAL& sum) { m_sum[band] = sum; }
		inline REALVec& GetSum() { return m_sum; }
		const inline REALVec& GetSum() const { return m_sum; }

		inline REAL GetSumsq(const int& band) const { return m_sumsq[band]; }
		inline void SetSumsq(const int& band, const REAL& sum) { m_sumsq[band] = sum; }
		inline REALVec& GetSumsq() { return m_sumsq; }
		const inline REALVec& GetSumsq() const { return m_sumsq; }

		inline void AddBoundaryLine(const CBoundaryLine& bound) { m_bounds.push_back(bound); }
		inline BoundaryLineVec& GetBounds() { return m_bounds; }
		inline const BoundaryLineVec& GetBounds() const { return m_bounds; }

		inline int& MinX() { return m_minx; }
		inline int& MaxX() { return m_maxx; }
		inline const int& MinX() const { return m_minx; }
		inline const int& MaxX() const { return m_maxx; }

		int MinY() const;
		int MaxY() const;

		void CalculateAvgDissim();
		inline REAL GetAvgDissim() const { return m_avgDissim; }

		void CalculatePerimeter();
		inline REAL& Perimeter() { return m_perimeter; }
		inline const REAL& Perimeter() const { return m_perimeter; }

	public:
		bool                                      m_utilFlag;
	private:										 
		int                                         m_id;
		int                                         m_numpix;
		int                                         m_minx;
		int                                         m_maxx;
		REAL                                     m_avgDissim;
		REAL                                     m_perimeter;
		REALVec                               m_sum;
		REALVec                               m_sumsq;
		NeighborList                         m_neighbors;
		BoundaryLineVec                  m_bounds;
	};

	//---------------------------------------------------------------
	typedef std::hash_map<int,CRegionObject*> ObjectMap;
	
	//---------------------------------------------------------------
	void _mergeBoundaryline(BoundaryLineVec& bounds,const BoundaryLineVec& other,int&minx,int&maxx);

	//---------------------------------------------------------------
	void _mergeBoundaryline(const BoundaryLineVec& lhs,const BoundaryLineVec& rhs,BoundaryLineVec& bounds,int&minx,int&maxx);

	//---------------------------------------------------------------
	void _mergeObject(CRegionObject* obj, const CRegionObject* other);

	//---------------------------------------------------------------
	void _pushBackPixelObject(CRegionObject* obj, const CRegionObject* other);

	//---------------------------------------------------------------
	void _getUpperRowBounds(const BoundaryLineVec& bounds,const int& idx,std::vector<int>& upperRowBounds);
	void _getUnderRowBounds(const BoundaryLineVec& bounds,const int& idx,std::vector<int>& underRowBounds);
	bool _containsPixel(const BoundaryLineVec& bounds,std::vector<int>& nBounds,const int& row,const int& col);

	//---------------------------------------------------------------
	REAL _calculatePerimeter(const BoundaryLineVec& bounds);

	
}
